﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using NumericalMethods;
using NumericalMethods.FourthBlog;

using MathExpr;

using System.Collections;

using System.Runtime.InteropServices;    // needed to call external
                                         // application (winAPI dll)


namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {

        InvalidCastException e;

        //Numero de iteraciones del método de Newton Raphson
        Int32 numeroiteraciones;

        //Numero de ecuaciones del sistema de ecuaciones
        Int16 numeroecuaciones;

        //Lista de cadenas que guardan las ecuaciones del sistema
        List<String> ecuacion = new List<String>();
        
        //Lista de parametros que guardan los valores y nombres de las variables del sistema
        List<Parameter> E = new List<Parameter>();
        
        //Parametro para inicializar la lista de parámetros que guardan las variables del sistema de ecuaciones
        Parameter Eprueba = new Parameter(0.0, "");
        
        //Lista de cadenas para gardar las variables del sistema de ecuaciones
        List<String> variable = new List<String>();
        
        //Interpretador de ecuaciones
        Parser par = new Parser();
        
        //Declaración de un evaluador para calcular el valor de la función en un punto f(xo)
        Evaluator ev = new Evaluator();

        //Guarda las ecuaciones para enviarlas al Parse para su interpretación
        List<Node> listanudos = new List<Node>();
        
        //Para graficar los resultados después de solucionar el sistema de ecuaciones y evaluar el error
        //PENDIENTE DE IMPLEMENTACIÓN
        //List<Doouble> listaresultados = new List<Double>();

        //TextBoxes para guardar las ecuaciones
        private ArrayList textboxes=new ArrayList();
        //TextBoxes para guardar las condiciones inciales
        private ArrayList textboxes1 = new ArrayList();
        //TextBoxes para guardar los resultados
        private ArrayList textboxes2 = new ArrayList();
        //Labels2 lista de etiquetas de los resultados del sistema de ecuaciones
        private ArrayList labels2 = new ArrayList();

        private ArrayList textboxes3 = new ArrayList();
        //Labels2 lista de etiquetas de los resultados del sistema de ecuaciones
        private ArrayList labels3= new ArrayList();

        private ArrayList textboxes4 = new ArrayList();
        //Labels2 lista de etiquetas de los resultados del sistema de ecuaciones
        private ArrayList labels4 = new ArrayList();
        
        //Para guardar las variables del sistema de ecuaciones
        List<Parameter> parameters =new List<Parameter>();
               

        public Form1()
        {
            InitializeComponent();
            //Numero de Cuadros de Texto
            numeroecuaciones = Convert.ToInt16(textBox9.Text);
            //Numero de iteraciones del metodo de NewtonRaphson
            textBox5.Text = Convert.ToString(numeroiteraciones);
        }
        
        //Botón de RESOLVER
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {

                if (textBox5.Text == "0")
                {
                    textBox5.Text = "10";
                }

                textBox5.Enabled = false;
                //Creación dinámica de las variables/parametros .Pendiente crear una structura que contenga nombre y valor de variables
                //Crear las variables conforme se crean los elementos y las corrientes 
                //Es muy  importante que en este bucle se asigna el nombre "Ei" a las variables
                for (int numvar = 1; numvar < numeroecuaciones + 1; numvar++)
                {
                    variable.Add("");
                    variable[numvar - 1] = "E" + Convert.ToString(numvar);
                    // Parameter E1 = new Parameter(0.0, variable[numvar - 1]);            
                    E.Add(Eprueba);
                    E[numvar - 1] = new Parameter(0.0, variable[numvar - 1]);
                    E[numvar - 1].DerivativeStep = Convert.ToDouble(textBox6.Text);
                }

                // TODO INCLUDE NEW VALUES BELOW TO INITILIZE THE VARIABLES
                // Incicialización estática de las variables 
                //ev[variable[0]] = 1.5;
                //ev[variable[1]] = 3.5;
                //E[0].Value = 1.5;
                //E[1].Value = 3.5;
                //ev[variable[2]] = 1.5;
                //ev[variable[3]] = 3.5;

                // Otra para un futuro será la opción de crear las variables mediante número aleatorio

                // Incialización dinámica de las variables tomando los valores de los TextBoxes creados dinámicamente
                for (int j = 0; j < numeroecuaciones; j++)
                {
                    //Inicialización de variables
                    ev[variable[j]] = Convert.ToDouble(((TextBox)this.textboxes1[j]).Text);
                    E[j].Value = Convert.ToDouble(((TextBox)this.textboxes1[j]).Text);
                    //Inicialización de las ecuaciones con las expresiones insertadas en los TextBoxes
                    if (((TextBox)this.textboxes[j]).Text == "") 
                    {
                        MessageBox.Show("Error Blank space in Equation input TextBox. Please review enter data and try again.");

                        goto errorequation;
                    }
                    
                    ecuacion[j] = ((TextBox)this.textboxes[j]).Text;
                }

                

                //En este bucle se envian las ecuaciones al PARSE paraque interprete las ecuaciones para su posterior evaluacion
                for (int i = 0; i < numeroecuaciones; i++)
                {
                    listanudos.Add(0);
                    listanudos[i] = par.Parse(ecuacion[i]);
                }

                // Func<double>[] functions = new Func<double>[]
                //{
                //  () => 0.005 * (100.0 - E[0] - 2.0 * E[1]) * (1.0 - E[0] - E[2]) - 100.0 * E[0],
                //  () => 500.0 * Math.Pow(100.0 - E[0] - 2.0 * E[1], 2.0) - 100.0 * E[1],
                //  () => 0.5 * (100.0 - E[0] - E[2] - 2.0 * E[3]) - 100.0 * E[2],
                //  () => 10000.0 * Math.Pow(100.0 * E[2] - 2.0 * E[3], 2.0) - 100.0 * E[3]
                //};

                //Creamos un ARRAY para guardar los paráemteros creados E[i].
                //Cada uno de los parámetros E[i] guarda una variable con su valor y nombre
                //Hacer un For para asignar automáticamente los valores del array parameters
                for (int i = 0; i < numeroecuaciones; i++)
                {
                    parameters.Add(E[i]);
                }
                //Enviar a la función NewtonRaphson a traves de sus argumentos un puntero a la lista de Nudos (ecuaciones)
                //Enviar el puntero "listanudos" para acceder a las funciones/ecuaciones contenidas en el array "listanudos[i]"

                // Enviar las variables contenidas en el array variable[]
                //También enviar el valor inicial de las variables contenidos en el array ev[]

                // Es decir, enviar a la función NewtonRaphson toda la información que le haga falta calcular el método numérico NewtonRaphson   
                // Newton Raphson necesita las variables/parameteros, sus valores y las ecuaciones/funciones

                numeroiteraciones = Convert.ToInt16(textBox5.Text);

                NewtonRaphson1 nr = new NewtonRaphson1(numeroecuaciones, parameters, listanudos, variable);
                int contador;
                contador = 1;

            luis:
                for (int b = 0; b < numeroiteraciones; b++)
                {
                    //Activamos la consola para visualizar los resultados intermedios de los cálculos
                    Win32.AllocConsole();
                    //Escribimos el número de iteración de los resultados intermedios
                    Console.WriteLine(Convert.ToString("Iteration Number: " + Convert.ToString(contador)));

                    //Llamada al objeto nr de la clase NewtonRaphson para realizar una iteracción
                    nr.Iterate();

                    for (int g = 0; g < numeroecuaciones; g++)
                    {
                        //Escribimos en los TextBoes los valores de las variables
                        ((TextBox)this.textboxes2[g]).Text = Convert.ToString(E[g].Value);

                        //Inicializamos las variables a los valores iniciales de los parámetros
                        for (int w = 0; w < numeroecuaciones; w++)
                        {
                            ev[variable[w]] = E[w].Value;
                        }

                        //Calculamos los valores de las funciones/ecuaciones con los valores de las variables 
                        ((TextBox)this.textboxes3[g]).Text = Convert.ToString(ev.Evaluate(listanudos[g]));

                        //Escribimos en la consola los nombre y valores de los parametros
                        Console.WriteLine(Convert.ToString(E[g].Nombre + ":" + E[g].Value));
                        //Escribimos en la consola el Error de la funciones/ecuaciones
                        Console.WriteLine(Convert.ToString("Error " + "E" + "(x)" + ":" + Convert.ToString(ev.Evaluate(listanudos[g]))));


                        if (E[g].Value > Convert.ToDouble(textBox2.Text) || E[g].Value < Convert.ToDouble(textBox3.Text))
                        {
                            MessageBox.Show("No Convergence Error, change initial conditions.", "No Convergence Error !!!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            goto salida;
                        }

                        if (contador > numeroiteraciones)
                        {
                            MessageBox.Show("Increase Number of Iterations. Iterations Nº:" + Convert.ToString(contador), "Error No Convergencia del Método", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            goto salida;
                        }
                    }

                    contador++;

                }

                for (int g = 0; g < numeroecuaciones; g++)
                {

                    for (int w = 0; w < numeroecuaciones; w++)
                    {

                        //Asignamos los valores de los parametros a las variables
                        ev[variable[w]] = E[w].Value;
                    }

                    //Calculamos el valor de la función en las variables inicializadas
                    if ((ev.Evaluate(listanudos[g]) > Convert.ToDouble(textBox1.Text)) || (ev.Evaluate(listanudos[g]) < -(Convert.ToDouble(textBox1.Text))))
                    {
                        //MessageBox.Show("Valor del Error:"+Convert.ToString((ev.Evaluate(listanudos[g]))), "Error Fuera de Rango Superior a:" + textBox1.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        numeroiteraciones = 1;
                        goto luis;
                    }
                }

            salida:
                //Esperamos que el usuario pulse una tecla del teclado para finalizar/ocultar la consola
                Console.WriteLine("Iterations Finished, Push a Key to Continue...");
                Console.ReadKey();
                //Finalizamos/cerramos la consola
                Win32.FreeConsole();

                textBox5.Text = Convert.ToString(contador);

                //label6.ForeColor = Color.Red;
                //label6.Text = "Número FINAL de iteraciones:";
                //label6.Location = new System.Drawing.Point(232,13);

                //Llamamos al destuctor para inicializar todas las variables locales de la clase NewtonRahpson1
                // y poder llevar a cabo otro cálculo nuevo.
                nr.destructor();

               errorequation:

                button1.Enabled = false;
                button4.Enabled = true;
            }

            catch 
            {
                Win32.FreeConsole();
                 MessageBox.Show("Input Data ERROR !!!.","Error in Input Data, please review it, and Run the Application again.", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);                    
                // Reset Problem due to Error in Input Data.
                button4.PerformClick();
                button2.Enabled = true;
                button1.Enabled = false;

                Application.Exit();
            }
        }    

        //Crear controles en tiempo real durante la ejecución del programa
        private void button2_Click(object sender, EventArgs e)
        {
             numeroecuaciones = Convert.ToInt16(textBox9.Text);

             label4.Visible = true;
             label8.Visible = true;

             if (numeroecuaciones > 10)
             {
                 label4.Visible = false;
                 label8.Visible = false;
             }

             int i = 0;

             numeroecuaciones = Convert.ToInt16(textBox9.Text);

            //Creamos en tiempo real los TextBoxes para introducir las ecuaciones
             for (i = 0; i < numeroecuaciones; i++)
             {
                 this.textboxes.Add(new TextBox());
                 ((TextBox)this.textboxes[i]).Location = new System.Drawing.Point(40, 80 + i * 40);
                 ((TextBox)this.textboxes[i]).Name = "TextBoxName" + i.ToString();
                 ((TextBox)this.textboxes[i]).Size = new System.Drawing.Size(350, 20);
                 ((TextBox)this.textboxes[i]).TabIndex = i + 2;
                 ((TextBox)this.textboxes[i]).Text = String.Empty;
                 //((TextBox)this.textboxes[i]).BackColor = Color.Green;
                 this.Controls.Add(((TextBox)this.textboxes[i]));
             }

             int j = 0;
            //Creamos en tiempo real los TextBoxes para introducir las ecuaciones y sus valores iniciales
             for (j = 0; j < numeroecuaciones; j++)
             {
                 this.textboxes1.Add(new TextBox());
                 ((TextBox)this.textboxes1[j]).Location = new System.Drawing.Point(442, 80 + j * 40);
                 ((TextBox)this.textboxes1[j]).Name = "TextBoxName" + j.ToString();
                 ((TextBox)this.textboxes1[j]).Size = new System.Drawing.Size(59, 20);
                 ((TextBox)this.textboxes1[j]).TabIndex = j + 2;
                 ((TextBox)this.textboxes1[j]).Text = "1";
                 //((TextBox)this.textboxes1[j]).BackColor = Color.Yellow;
                 this.Controls.Add(((TextBox)this.textboxes1[j]));
                 ecuacion.Add("");
             }

             int r;
            //Creamos en tiempo real los TextBoxes para introducir los valores iniciales
             for (r = 0; r < numeroecuaciones; r++)
             {
                 this.textboxes2.Add(new TextBox());
                 ((TextBox)this.textboxes2[r]).Location = new System.Drawing.Point(718, 80 + r * 40);
                 ((TextBox)this.textboxes2[r]).Name = "TextBoxName" + j.ToString();
                 ((TextBox)this.textboxes2[r]).Size = new System.Drawing.Size(100, 20);
                 ((TextBox)this.textboxes2[r]).TabIndex = r + 2;
                 ((TextBox)this.textboxes2[r]).Text = "0";
                 ((TextBox)this.textboxes2[r]).Enabled = false;
                 ((TextBox)this.textboxes2[r]).BackColor = Color.Yellow;
                 this.Controls.Add(((TextBox)this.textboxes2[r]));
                 
                 this.labels2.Add(new Label());
                 ((Label)this.labels2[r]).Location = new System.Drawing.Point(690, 80 + r * 40);
                 ((Label)this.labels2[r]).Name = "LabelName" + j.ToString();
                 ((Label)this.labels2[r]).Size = new System.Drawing.Size(35,20);
                 ((Label)this.labels2[r]).TabIndex = r + 2;
                 ((Label)this.labels2[r]).Text = "E"+Convert.ToString(r)+":";
                 this.Controls.Add(((Label)this.labels2[r]));
             }

             int q;
             //Creamos en tiempo real los TextBoxes para introducir los resultados de las funciones/ecuaciones
             for (q = 0; q < numeroecuaciones; q++)
             {
                 this.textboxes3.Add(new TextBox());
                 ((TextBox)this.textboxes3[q]).Location = new System.Drawing.Point(900, 80 + q * 40);
                 ((TextBox)this.textboxes3[q]).Name = "TextBoxName" + q.ToString();
                 ((TextBox)this.textboxes3[q]).Size = new System.Drawing.Size(100, 20);
                 ((TextBox)this.textboxes3[q]).TabIndex = q + 2;
                 ((TextBox)this.textboxes3[q]).Text = "";
                 ((TextBox)this.textboxes3[q]).Enabled = false;
                 ((TextBox)this.textboxes3[q]).BackColor = Color.Yellow;
                 this.Controls.Add(((TextBox)this.textboxes3[q]));

                 this.labels3.Add(new Label());
                 ((Label)this.labels3[q]).Location = new System.Drawing.Point(860, 80 + q * 40);
                 ((Label)this.labels3[q]).Name = "LabelName" + q.ToString();
                 ((Label)this.labels3[q]).Size = new System.Drawing.Size(35, 20);
                 ((Label)this.labels3[q]).TabIndex = q + 2;
                 ((Label)this.labels3[q]).Text = "E" + Convert.ToString(q) + "(x)"+":";
                 this.Controls.Add(((Label)this.labels3[q]));
             }

             button2.Enabled = false;
             button3.Enabled = true;
        }

        //Botón de copiar ecuaciones
        private void button3_Click(object sender, EventArgs e)
        {
               // Creación dinámica de las ecuaciones
               //ecuacion.Add("");
               // ecuacion[0] = "0.005 * (100.0 - E1 - 2.0 * E2) * (1.0 - E1 - E3) - 100.0 * E1";
               // ((TextBox)this.textboxes[0]).Text=ecuacion[0];
                ecuacion[0] = "(E1^2)+E1*E2-10";
                ((TextBox)this.textboxes[0]).Text=ecuacion[0];
            
                //ecuacion.Add("");
                //ecuacion[1] = "500.0 *(100.0 - E1 - 2.0 * E2)^2.0 - 100.0 * E2";
                //((TextBox)this.textboxes[1]).Text = ecuacion[1];
                ecuacion[1] = "E2+(3*E1*(E2^2))-57";
                ((TextBox)this.textboxes[1]).Text = ecuacion[1];
            
                //ecuacion.Add("");
                //ecuacion[2] = "0.5 * (100.0 - E1 - E3 - 2.0 * E4) - 100.0 * E3";
                //((TextBox)this.textboxes[2]).Text = ecuacion[2];
                
                //ecuacion.Add("");
                //ecuacion[3] = "10000.0 * (100.0 * E3 - 2.0 * E4)^2.0 - 100.0 * E4";
                //((TextBox)this.textboxes[3]).Text = ecuacion[3];
                button3.Enabled = false;
                button1.Enabled = true;

        }

        //Botón para inicializar la Aplicación
        private void button4_Click(object sender, EventArgs e)
        {
            textBox5.Enabled = true;
            textBox9.Text = "2";

            //Eliminación de ecuaciones
            for (int j = 0; j < numeroecuaciones; j++)
            {
                ecuacion.Remove(((TextBox)this.textboxes[j]).Text);
            }

            //Eliminación de variables y parametros
            for (int numvar = 0; numvar < numeroecuaciones; numvar++)
            {
                variable[0] = "E" + Convert.ToString(0);
                variable.Remove(variable[0]); 
                E.RemoveAt(0);
            }  

            int r;
            //Eliminación de TextBoxes y Labels creadas en tiempo real 
            for (r = 0; r < numeroecuaciones; r++)
            {
                this.Controls.Remove(((TextBox)this.textboxes[r]));
                this.Controls.Remove(((TextBox)this.textboxes1[r]));
                this.Controls.Remove(((TextBox)this.textboxes2[r]));
                this.Controls.Remove(((Label)this.labels2[r]));
                this.Controls.Remove(((TextBox)this.textboxes3[r]));
                this.Controls.Remove(((Label)this.labels3[r]));
            }
            //Para permitir realizar dos cálculos cosecutivos es necesario inicializar todas las variables
            //del programa a su valor original.TRABAJO PENDIENTE POR HACER.
            // numeroecuaciones = 0;

            button4.Enabled = false;
            button2.Enabled = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button4.Enabled = false;
            button3.Enabled = false;
            textBox5.Text = "100";
        }

        private void label5_Click(object sender, EventArgs e)
        {

        }

        private void button5_Click(object sender, EventArgs e)
        {
            About LuisCocoEnriquez = new About();
            LuisCocoEnriquez.Show();
        }
       
     }

    public class Win32
    {
        [DllImport("kernel32.dll")]
        public static extern Boolean AllocConsole();
        [DllImport("kernel32.dll")]
        public static extern Boolean FreeConsole();
    }

}

